<script setup lang="ts" name="kg">
import { onMounted, reactive, ref } from 'vue';
import * as d3 from 'd3';
import { useRouter } from 'vue-router'
import markdown from './markdown.vue';
const router = useRouter()



const graph = ref<HTMLElement | null>(null);

interface Node {
  id: string;
  label: string;
  groups: string;
  note: string;
}

interface Link {
  source: string;
  target: string;
  category: string;
}

const selectnode = ref<Node>({
  id: '',
  label: '',
  groups: '',
  note: ''
});
const selectlink = ref<Link>({
  source: '',
  target: '',
  category: ''
});


const nodes = ref<Node[]>([
  {
    "id": "1", "groups": '1', "label": "Node A", "note": `## 标题1
> import
[md-editor-v3@4.12.4](https://imzbf.github.io/md-editor-v3/zh-CN/index)`},
  { "id": "2", "groups": '2', "label": "Node B", "note": `## 标题1Node` },
  { "id": "3", "groups": '2', "label": "Node C", "note": `## Node C` },
  { "id": "4", "groups": '3', "label": "Node D", "note": `## 标题1Node D` },
  { "id": "5", "groups": '3', "label": "Node E", "note": `## 标题1Node E` },
  { "id": "6", "groups": '1', "label": "Node F", "note": `## 标题1Node FNode G` },
  { "id": "7", "groups": '2', "label": "Node G", "note": `## 标题1Node G` },
  { "id": "8", "groups": '3', "label": "Node H", "note": `## 标题1Node H` }
]);
const links = ref<Link[]>([
  { "source": "1", "target": "2", "category": "使用" },
  { "source": "2", "target": "3", "category": "属于" },
  { "source": "3", "target": "4", "category": "属于" },
  { "source": "4", "target": "5", "category": "属于" },
  { "source": "5", "target": "6", "category": "使用" },
  { "source": "6", "target": "7", "category": "属于" },
  { "source": "7", "target": "8", "category": "使用" },
  { "source": "8", "target": "1", "category": "属于" },
  { "source": "2", "target": "8", "category": "使用" },
  { "source": "3", "target": "6", "category": "使用" },
]);

onMounted(updateGraph);

function updateGraph() {
  if (!graph.value) return;

  // 定义图的宽高
  const width = 800;
  const height = window.innerHeight - 130;
  const colorScale = d3.scaleOrdinal(d3.schemeCategory10); // 类别颜色比例尺
  const simulation = d3.forceSimulation(nodes.value)
    .force("link", d3.forceLink(links.value).id(d => d.id).distance(150))
    .force("charge", d3.forceManyBody())
    .force("center", d3.forceCenter(width / 2, height / 2))
    .force("collision", d3.forceCollide(50));

  const svg = d3.select(graph.value)
    .append('svg')
    .attr('width', width)
    .attr('height', height);

  const labels = svg.append("g")
    .attr("class", "labels")
    .selectAll("text")
    .data(nodes.value)
    .enter().append("text")
    .text(d => d.label) // 假设每个节点对象有一个id属性作为名称
    .attr("x", d => d.x)
    .attr("y", d => d.y)
    .attr("dx", 25) // 文本相对于节点中心的偏移量
    .attr("dy", ".35em") // 垂直对齐方式
    .style("fill", "#555") // 文本颜色
    .style("font-size", "12px"); // 文本大小

  // 绘制连线和名称
  const link = svg.append("g")
    .attr("stroke", "#999")
    .selectAll("g")
    .data(links.value)
    .enter().append("g");
  // 绘制曲线连线
  link.append("path")
    .attr("fill", "none")
    .attr("stroke", d => colorScale(d.category))
    .attr("stroke-width", 3)
    .attr("marker-end", "url(#end)") // Use the defined arrow marker
    .on("mouseover", function () {
      d3.select(this).classed("link-hover", true); // 鼠标悬停时添加类
    })
    .on("mouseout", function () {
      d3.select(this).classed("link-hover", false); // 鼠标移出时移除类
    })
    .on("click", function (event, l) {
      showmarkdownlink(l)
    });

  link.append("text")
    .text(d => d.category)
    .attr("font-size", "10px")
    .attr("x", d => (d.source.x + d.target.x) / 2)
    .attr("y", d => (d.source.y + d.target.y) / 2);

  // 绘制节点
  svg.append("g")
    .selectAll("circle")
    .data(nodes.value)
    .enter()
    .append("circle")
    .attr("r", 20)
    .attr("fill", d => colorScale(d.groups))
    .call(drag(simulation, svg))
    .on("mouseover", function () {
      d3.select(this).attr("r", 30); // 鼠标悬停时增加节点大小
    })
    .on("mouseout", function () {
      d3.select(this).attr("r", 20); // 鼠标悬停时增加节点大小
    })
    .on("click", function (event, d) {
      showmarkdown(d)
    })


  // Add defs block and define arrow marker
  svg.append('defs').selectAll('marker')
    .data(['end']) // Just one marker named "end"
    .enter().append('marker')
    .attr('id', String)
    .attr('viewBox', '0 -7 10 10')
    .attr('refX', 23) // Adjust this value to move the arrow position
    .attr('refY', 0)
    .attr('markerWidth', 3)
    .attr('markerHeight', 5)
    .attr('orient', 'auto')
    .append('path')
    .attr('d', 'M0,-5L10,0L0,5');

  // 节点和链接的位置更新
  simulation.on("tick", () => {

    svg.selectAll("line")
      .attr("x1", (d: any) => d.source.x)
      .attr("y1", (d: any) => d.source.y)
      .attr("x2", (d: any) => d.target.x)
      .attr("y2", (d: any) => d.target.y);

    svg.selectAll("circle")
      .attr("cx", (d: any) => d.x)
      .attr("cy", (d: any) => d.y);

    link.selectAll("path")
      .attr("d", d => {
        const dx = d.target.x - d.source.x,
          dy = d.target.y - d.source.y,
          dr = Math.sqrt(dx * dx + dy * dy);
        const radius = 10; // 目标节点的半径
        const offsetX = (dx * radius) / dr;
        const offsetY = (dy * radius) / dr;
        return `M${d.source.x},${d.source.y}A${dr},${dr} 0 0,1 ${d.target.x - offsetX},${d.target.y - offsetY}`;
      });

    link.selectAll("text")
      .attr("x", d => (d.source.x + d.target.x) / 2)
      .attr("y", d => (d.source.y + d.target.y) / 2);

    // 更新文本标签的位置
    labels.attr("x", d => d.x)
      .attr("y", d => d.y);
  });

  const zoomHandler = d3.zoom()
    .scaleExtent([1, 5]) // 设置缩放范围最小和最大值
    .on("zoom", (event) => {
      svg.attr("transform", event.transform);
    });
  svg.call(zoomHandler);




};
// 实现拖拽
function drag(simulation: d3.Simulation<d3.SimulationNodeDatum, undefined>, svg: d3.Selection<SVGSVGElement, unknown, null, undefined>) {
  function dragstarted(event: any) {
    if (!event.active) simulation.alphaTarget(0.3).restart();
    event.subject.fx = event.subject.x;
    event.subject.fy = event.subject.y;
  }

  function dragged(event: any) {
    event.subject.fx = event.x;
    event.subject.fy = event.y;
  }

  function dragended(event: any) {
    if (!event.active) simulation.alphaTarget(0);
    event.subject.fx = null;
    event.subject.fy = null;
  }

  return d3.drag()
    .on("start", dragstarted)
    .on("drag", dragged)
    .on("end", dragended);
}

function showmarkdown(d: Node) {
  selectnode.value = d;

}

function showmarkdownlink(l: Link) {
  if (selectlink.value) {
    Object.assign(selectlink.value, l);
    console.log(selectlink.value);
  } else {
    throw new Error('selectlink ref is not initialized');
  }
}


</script>

<template>

  <el-container>
    <el-aside width="800px">
      <div ref="graph" class="force-graph">
        <!-- 定义箭头 -->
        <defs>
          <marker id="arrow" markerWidth="20" markerHeight="20" refX="10" refY="3" orient="auto"
            markerUnits="strokeWidth">
            <path d="M0,0 L0,12 L18,6 z" fill="#f00" />
          </marker>
        </defs>
      </div>
    </el-aside>
    <el-main>
      <markdown :pnode="selectnode" :plink="selectlink" />
    </el-main>
  </el-container>
</template>

<style>
.link-hover {
  stroke: rgb(0, 0, 0);
  /* 连线悬停时的颜色 */
  stroke-width: 3px;
  /* 连线悬停时的宽度 */
  transition: stroke-width 0.9s ease-in-out, stroke 0.2s ease-in-out;
  /* 平滑的过渡效果 */
}
</style>